]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
workspace: Use the new WorkspaceLayout for allocating window clones
authorJonas Dreßler <verdre@v0yd.nl>
Wed, 3 Jun 2020 16:17:54 +0000 (18:17 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Mon, 6 Jul 2020 21:16:15 +0000 (23:16 +0200)
Switch to the new WorkspaceLayout layout manager to allocate the window
clones of the overview properly using Clutters layouting mechanisms.

Since we now no longer make use of the fullGeometry, we can remove the
setFullGeometry() function from the Workspace class. Also we can stop
setting the actualGeometry on the Workspaces and WorkspaceViews and
instead just set the fixed position and size of the views to their
full or actual geometry. This also has the benefit that we no longer
have to set a custom clip, but can simply enable clip_to_allocation.

The geometry needs to be set inside a BEFORE_REDRAW later because
_updateWorkspacesActualGeometry() is called from a notify::allocation
handler.

This isn't doing any animations when showing/hiding the overview yet,
we'll add that in the next commit.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1305

data/theme/gnome-shell-sass/widgets/_window-picker.scss
js/ui/windowPreview.js
js/ui/workspace.js
js/ui/workspacesView.js

index 48d6f73f562926c626af826b6873d1c9d7e0af0f..1b93218517dbe9dfab6c384b2c09f1210996335f 100644 (file)
@@ -1,7 +1,7 @@
 /* Window Picker */
 
-$window_picker_spacing: $base_spacing * 2; // 16px
-$window_picker_padding: $base_padding * 2; // 16px
+$window_picker_spacing: $base_spacing; // 6px
+$window_picker_padding: $base_padding * 2; // 12px
 
 $window_thumbnail_border_color:transparentize($selected_fg_color, 0.65);
 
@@ -13,8 +13,8 @@ $window_clone_border_size: 6px;
 // Window picker
 .window-picker {
   // Space between window thumbnails
-  -horizontal-spacing: $window_picker_spacing;
-  -vertical-spacing: $window_picker_spacing;
+  spacing: $window_picker_spacing;
+
   // Padding for container around window thumbnails
   padding: $window_picker_padding;
 
index b7fc5efa5a17c63b3f8ee7f6a4a78968dd485748..69e3ee57487b581a9b4a3f5df51118412f7588d3 100644 (file)
@@ -237,8 +237,6 @@ var WindowPreview = GObject.registerClass({
             this._windowActor.connect('destroy', () => this.destroy());
 
         this._updateAttachedDialogs();
-        this.x = this.boundingBox.x;
-        this.y = this.boundingBox.y;
 
         let clickAction = new Clutter.ClickAction();
         clickAction.connect('clicked', () => this._activate());
index ef4fc3a492631a0ff4167d673f8c0292c17273fc..182f350ae9a8b2f8166087d33664fe83c988ad0a 100644 (file)
@@ -1,7 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported Workspace */
 
-const { Clutter, GLib, GObject, Meta, St } = imports.gi;
+const { Clutter, GLib, GObject, St } = imports.gi;
 
 const DND = imports.ui.dnd;
 const Main = imports.ui.main;
@@ -26,12 +26,6 @@ function _interpolate(start, end, step) {
     return start + (end - start) * step;
 }
 
-var WindowPositionFlags = {
-    NONE: 0,
-    INITIAL: 1 << 0,
-    ANIMATE: 1 << 1,
-};
-
 // Window Thumbnail Layout Algorithm
 // =================================
 //
@@ -367,28 +361,6 @@ var UnalignedLayoutStrategy = class extends LayoutStrategy {
     }
 };
 
-function padArea(area, padding) {
-    return {
-        x: area.x + padding.left,
-        y: area.y + padding.top,
-        width: area.width - padding.left - padding.right,
-        height: area.height - padding.top - padding.bottom,
-    };
-}
-
-function rectEqual(one, two) {
-    if (one == two)
-        return true;
-
-    if (!one || !two)
-        return false;
-
-    return one.x == two.x &&
-            one.y == two.y &&
-            one.width == two.width &&
-            one.height == two.height;
-}
-
 function animateAllocation(actor, box) {
     if (actor.allocation.equal(box) ||
         actor.allocation.get_width() === 0 ||
@@ -815,39 +787,23 @@ var WorkspaceLayout = GObject.registerClass({
 var Workspace = GObject.registerClass(
 class Workspace extends St.Widget {
     _init(metaWorkspace, monitorIndex) {
-        super._init({ style_class: 'window-picker' });
+        super._init({
+            style_class: 'window-picker',
+            layout_manager: new WorkspaceLayout(metaWorkspace, monitorIndex),
+        });
 
         // When dragging a window, we use this slot for reserve space.
         this._reservedSlot = null;
         this._reservedSlotWindow = null;
         this.metaWorkspace = metaWorkspace;
 
-        // The full geometry is the geometry we should try and position
-        // windows for. The actual geometry we allocate may be less than
-        // this, like if the workspace switcher is slid out.
-        this._fullGeometry = null;
-
-        // The actual geometry is the geometry we need to arrange windows
-        // in. If this is a smaller area than the full geometry, we'll
-        // do some simple aspect ratio like math to fit the layout calculated
-        // for the full geometry into this area.
-        this._actualGeometry = null;
-        this._actualGeometryLater = 0;
-
-        this._currentLayout = null;
-
         this.monitorIndex = monitorIndex;
         this._monitor = Main.layoutManager.monitors[this.monitorIndex];
 
         if (monitorIndex != Main.layoutManager.primaryIndex)
             this.add_style_class_name('external-monitor');
-        this.set_size(0, 0);
-
-        this._dropRect = new Clutter.Actor({ opacity: 0 });
-        this._dropRect._delegate = this;
-
-        this.add_actor(this._dropRect);
 
+        this.connect('style-changed', this._onStyleChanged.bind(this));
         this.connect('destroy', this._onDestroy.bind(this));
 
         const windows = global.get_window_actors().map(a => a.meta_window)
@@ -858,7 +814,7 @@ class Workspace extends St.Widget {
         this._windows = [];
         for (let i = 0; i < windows.length; i++) {
             if (this._isOverviewWindow(windows[i]))
-                this._addWindowClone(windows[i], true);
+                this._addWindowClone(windows[i]);
         }
 
         // Track window changes
@@ -872,68 +828,14 @@ class Workspace extends St.Widget {
                                                               this._windowEnteredMonitor.bind(this));
         this._windowLeftMonitorId = global.display.connect('window-left-monitor',
                                                            this._windowLeftMonitor.bind(this));
-        this._repositionWindowsId = 0;
-
-        this.leavingOverview = false;
-
-        this._positionWindowsFlags = 0;
-        this._positionWindowsId = 0;
-    }
+        this._layoutFrozenId = 0;
 
-    vfunc_map() {
-        super.vfunc_map();
-        this._syncActualGeometry();
+        // DND requires this to be set
+        this._delegate = this;
     }
 
     vfunc_get_focus_chain() {
-        return this.get_children().filter(c => c.visible).sort((a, b) => {
-            if (a instanceof WindowPreview && b instanceof WindowPreview)
-                return a.slotId - b.slotId;
-
-            return 0;
-        });
-    }
-
-    setFullGeometry(geom) {
-        if (rectEqual(this._fullGeometry, geom))
-            return;
-
-        this._fullGeometry = geom;
-
-        if (this.mapped)
-            this._recalculateWindowPositions(WindowPositionFlags.NONE);
-    }
-
-    setActualGeometry(geom) {
-        if (rectEqual(this._actualGeometry, geom))
-            return;
-
-        this._actualGeometry = geom;
-        this._actualGeometryDirty = true;
-
-        if (this.mapped)
-            this._syncActualGeometry();
-    }
-
-    _syncActualGeometry() {
-        if (this._actualGeometryLater || !this._actualGeometryDirty)
-            return;
-        if (!this._actualGeometry)
-            return;
-
-        this._actualGeometryLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
-            this._actualGeometryLater = 0;
-            if (!this.mapped)
-                return false;
-
-            let geom = this._actualGeometry;
-
-            this._dropRect.set_position(geom.x, geom.y);
-            this._dropRect.set_size(geom.width, geom.height);
-            this._updateWindowPositions(Main.overview.animationInProgress ? WindowPositionFlags.ANIMATE : WindowPositionFlags.NONE);
-
-            return false;
-        });
+        return this.layout_manager.getFocusChain();
     }
 
     _lookupIndex(metaWindow) {
@@ -959,232 +861,59 @@ class Workspace extends St.Widget {
             this._reservedSlotWindow = metaWindow;
             this._reservedSlot = this._windows[this._lookupIndex(metaWindow)];
         }
-
-        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
-    }
-
-    _recalculateWindowPositions(flags) {
-        this._positionWindowsFlags |= flags;
-
-        if (this._positionWindowsId > 0)
-            return;
-
-        this._positionWindowsId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
-            this._realRecalculateWindowPositions(this._positionWindowsFlags);
-            this._positionWindowsFlags = 0;
-            this._positionWindowsId = 0;
-            return false;
-        });
-    }
-
-    _realRecalculateWindowPositions(flags) {
-        if (this._repositionWindowsId > 0) {
-            GLib.source_remove(this._repositionWindowsId);
-            this._repositionWindowsId = 0;
-        }
-
-        let clones = this._windows.slice();
-        if (clones.length == 0)
-            return;
-
-        clones.sort((a, b) => {
-            return a.metaWindow.get_stable_sequence() - b.metaWindow.get_stable_sequence();
-        });
-
-        if (this._reservedSlot)
-            clones.push(this._reservedSlot);
-
-        this._currentLayout = this._computeLayout(clones);
-        this._updateWindowPositions(flags);
-    }
-
-    _updateWindowPositions(flags) {
-        if (this._currentLayout == null) {
-            this._recalculateWindowPositions(flags);
-            return;
-        }
-
-        // We will reposition windows anyway when enter again overview or when ending the windows
-        // animations with fade animation.
-        // In this way we avoid unwanted animations of windows repositioning while
-        // animating overview.
-        if (this.leavingOverview || this._animatingWindowsFade)
-            return;
-
-        let initialPositioning = flags & WindowPositionFlags.INITIAL;
-        let animate = flags & WindowPositionFlags.ANIMATE;
-
-        let layout = this._currentLayout;
-        let strategy = layout.strategy;
-
-        let [, , padding] = this._getSpacingAndPadding();
-        let area = padArea(this._actualGeometry, padding);
-        let slots = strategy.computeWindowSlots(layout, area);
-
-        const isOnCurrentWorkspace =
-            this.metaWorkspace === null || this.metaWorkspace.active;
-
-        for (let i = 0; i < slots.length; i++) {
-            let slot = slots[i];
-            const [x, y, cellWidth, cellHeight, clone] = slot;
-
-            clone.slotId = i;
-
-            // Positioning a window currently being dragged must be avoided;
-            // we'll just leave a blank spot in the layout for it.
-            if (clone.inDrag)
-                continue;
-
-            const cloneWidth = cellWidth;
-            const cloneHeight = cellHeight;
-
-            if (!clone.positioned) {
-                // This window appeared after the overview was already up
-                // Grow the clone from the center of the slot
-                clone.x = x + cloneWidth / 2;
-                clone.y = y + cloneHeight / 2;
-                clone.width = 0;
-                clone.height = 0;
-                clone.positioned = true;
-            }
-
-            if (animate && isOnCurrentWorkspace) {
-                if (!clone.metaWindow.showing_on_its_workspace()) {
-                    /* Hidden windows should fade in and grow
-                     * therefore we need to resize them now so they
-                     * can be scaled up later */
-                    if (initialPositioning) {
-                        clone.opacity = 0;
-                        clone.x = x;
-                        clone.y = y;
-                        clone.width = cloneWidth;
-                        clone.height = cloneHeight;
-                    }
-
-                    clone.ease({
-                        opacity: 255,
-                        mode: Clutter.AnimationMode.EASE_IN_QUAD,
-                        duration: Overview.ANIMATION_TIME,
-                    });
-                }
-
-                this._animateClone(clone, x, y, cloneWidth, cloneHeight);
-            } else {
-                // cancel any active tweens (otherwise they might override our changes)
-                clone.remove_all_transitions();
-                clone.set_position(x, y);
-                clone.set_size(cloneWidth, cloneHeight);
-                clone.set_opacity(255);
-            }
-        }
     }
 
     syncStacking(stackIndices) {
-        let clones = this._windows.slice();
-        clones.sort((a, b) => {
-            let indexA = stackIndices[a.metaWindow.get_stable_sequence()];
-            let indexB = stackIndices[b.metaWindow.get_stable_sequence()];
-            return indexA - indexB;
-        });
-
-        for (let i = 0; i < clones.length; i++) {
-            let clone = clones[i];
-            if (i == 0) {
-                clone.setStackAbove(this._dropRect);
-            } else {
-                let previousClone = clones[i - 1];
-                clone.setStackAbove(previousClone);
-            }
-        }
-    }
-
-    _animateClone(clone, x, y, width, height) {
-        clone.ease({
-            x, y,
-            width, height,
-            duration: Overview.ANIMATION_TIME,
-            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
-        });
-    }
-
-    _delayedWindowRepositioning() {
-        let [x, y] = global.get_pointer();
-
-        let pointerHasMoved = this._cursorX != x && this._cursorY != y;
-        let inWorkspace = this._fullGeometry.x < x && x < this._fullGeometry.x + this._fullGeometry.width &&
-                           this._fullGeometry.y < y && y < this._fullGeometry.y + this._fullGeometry.height;
-
-        if (pointerHasMoved && inWorkspace) {
-            // store current cursor position
-            this._cursorX = x;
-            this._cursorY = y;
-            return GLib.SOURCE_CONTINUE;
-        }
-
-        let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
-        for (let i = 0; i < this._windows.length; i++) {
-            if (this._windows[i] == actorUnderPointer)
-                return GLib.SOURCE_CONTINUE;
-        }
-
-        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
-        this._repositionWindowsId = 0;
-        return GLib.SOURCE_REMOVE;
+        this.layout_manager.syncStacking(stackIndices);
     }
 
     _doRemoveWindow(metaWin) {
-        let win = metaWin.get_compositor_private();
-
         let clone = this._removeWindowClone(metaWin);
 
-        if (clone) {
-            // If metaWin.get_compositor_private() returned non-NULL, that
-            // means the window still exists (and is just being moved to
-            // another workspace or something), so set its overviewHint
-            // accordingly. (If it returned NULL, then the window is being
-            // destroyed; we'd like to animate this, but it's too late at
-            // this point.)
-            if (win) {
-                let [stageX, stageY] = clone.get_transformed_position();
-                const [transformedWidth, transformedHeight] =
-                    clone.get_transformed_size();
-
-                metaWin._overviewHint = {
-                    x: stageX,
-                    y: stageY,
-                    width: transformedWidth,
-                    height: transformedHeight,
-                };
-            }
-            clone.destroy();
-        }
+        if (!clone)
+            return;
+
+        clone.destroy();
 
         // We need to reposition the windows; to avoid shuffling windows
         // around while the user is interacting with the workspace, we delay
         // the positioning until the pointer remains still for at least 750 ms
         // or is moved outside the workspace
+        this.layout_manager.layout_frozen = true;
 
-        // remove old handler
-        if (this._repositionWindowsId > 0) {
-            GLib.source_remove(this._repositionWindowsId);
-            this._repositionWindowsId = 0;
+        if (this._layoutFrozenId > 0) {
+            GLib.source_remove(this._layoutFrozenId);
+            this._layoutFrozenId = 0;
         }
 
-        // setup new handler
-        let [x, y] = global.get_pointer();
-        this._cursorX = x;
-        this._cursorY = y;
+        let [oldX, oldY] = global.get_pointer();
+
+        this._layoutFrozenId = GLib.timeout_add(
+            GLib.PRIORITY_DEFAULT,
+            WINDOW_REPOSITIONING_DELAY,
+            () => {
+                const [newX, newY] = global.get_pointer();
+                const pointerHasMoved = oldX !== newX || oldY !== newY;
+                const actorUnderPointer = global.stage.get_actor_at_pos(
+                    Clutter.PickMode.REACTIVE, newX, newY);
+
+                if ((pointerHasMoved && this.contains(actorUnderPointer)) ||
+                    this._windows.some(w => w.contains(actorUnderPointer))) {
+                    oldX = newX;
+                    oldY = newY;
+                    return GLib.SOURCE_CONTINUE;
+                }
 
-        this._currentLayout = null;
-        this._repositionWindowsId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, WINDOW_REPOSITIONING_DELAY,
-            this._delayedWindowRepositioning.bind(this));
-        GLib.Source.set_name_by_id(this._repositionWindowsId, '[gnome-shell] this._delayedWindowRepositioning');
+                this.layout_manager.layout_frozen = false;
+                this._layoutFrozenId = 0;
+                return GLib.SOURCE_REMOVE;
+            });
+
+        GLib.Source.set_name_by_id(this._layoutFrozenId,
+            '[gnome-shell] this._layoutFrozenId');
     }
 
     _doAddWindow(metaWin) {
-        if (this.leavingOverview)
-            return;
-
         let win = metaWin.get_compositor_private();
 
         if (!win) {
@@ -1224,23 +953,16 @@ class Workspace extends St.Widget {
             return;
         }
 
-        let clone = this._addWindowClone(metaWin, false);
-
-        if (metaWin._overviewHint) {
-            let x = metaWin._overviewHint.x - this.x;
-            let y = metaWin._overviewHint.y - this.y;
-            const width = metaWin._overviewHint.width;
-            const height = metaWin._overviewHint.height;
-            delete metaWin._overviewHint;
+        this._addWindowClone(metaWin);
 
-            clone.positioned = true;
+        if (this._layoutFrozenId > 0) {
+            // If a window was closed before, unfreeze the layout to ensure
+            // the new window is immediately shown
+            this.layout_manager.layout_frozen = false;
 
-            clone.set_position(x, y);
-            clone.set_size(width, height);
+            GLib.source_remove(this._layoutFrozenId);
+            this._layoutFrozenId = 0;
         }
-
-        this._currentLayout = null;
-        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
     }
 
     _windowAdded(metaWorkspace, metaWin) {
@@ -1275,7 +997,7 @@ class Workspace extends St.Widget {
 
     fadeToOverview() {
         // We don't want to reposition windows while animating in this way.
-        this._animatingWindowsFade = true;
+        this.layout_manager.layout_frozen = true;
         this._overviewShownId = Main.overview.connect('shown', this._doneShowingOverview.bind(this));
         if (this._windows.length == 0)
             return;
@@ -1319,7 +1041,7 @@ class Workspace extends St.Widget {
     }
 
     fadeFromOverview() {
-        this.leavingOverview = true;
+        this.layout_manager.layout_frozen = true;
         this._overviewHiddenId = Main.overview.connect('hidden', this._doneLeavingOverview.bind(this));
         if (this._windows.length == 0)
             return;
@@ -1327,9 +1049,9 @@ class Workspace extends St.Widget {
         for (let i = 0; i < this._windows.length; i++)
             this._windows[i].remove_all_transitions();
 
-        if (this._repositionWindowsId > 0) {
-            GLib.source_remove(this._repositionWindowsId);
-            this._repositionWindowsId = 0;
+        if (this._layoutFrozenId > 0) {
+            GLib.source_remove(this._layoutFrozenId);
+            this._layoutFrozenId = 0;
         }
 
         if (this.metaWorkspace !== null && !this.metaWorkspace.active)
@@ -1375,10 +1097,6 @@ class Workspace extends St.Widget {
         clone.hideOverlay(false);
 
         if (clone.metaWindow.showing_on_its_workspace()) {
-            clone.x = clone.boundingBox.x;
-            clone.y = clone.boundingBox.y;
-            clone.width = clone.boundingBox.width;
-            clone.height = clone.boundingBox.height;
             clone.ease({
                 opacity,
                 duration,
@@ -1391,20 +1109,18 @@ class Workspace extends St.Widget {
     }
 
     zoomToOverview() {
-        // Position and scale the windows.
-        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
     }
 
     zoomFromOverview() {
-        this.leavingOverview = true;
-
         for (let i = 0; i < this._windows.length; i++)
             this._windows[i].remove_all_transitions();
 
-        if (this._repositionWindowsId > 0) {
-            GLib.source_remove(this._repositionWindowsId);
-            this._repositionWindowsId = 0;
+        if (this._layoutFrozenId > 0) {
+            GLib.source_remove(this._layoutFrozenId);
+            this._layoutFrozenId = 0;
         }
+
+        this.layout_manager.layout_frozen = true;
         this._overviewHiddenId = Main.overview.connect('hidden', this._doneLeavingOverview.bind(this));
 
         if (this.metaWorkspace !== null && !this.metaWorkspace.active)
@@ -1421,10 +1137,6 @@ class Workspace extends St.Widget {
 
         if (clone.metaWindow.showing_on_its_workspace()) {
             clone.ease({
-                x: clone.boundingBox.x,
-                y: clone.boundingBox.y,
-                width: clone.boundingBox.width,
-                height: clone.boundingBox.height,
                 opacity: 255,
                 duration: Overview.ANIMATION_TIME,
                 mode: Clutter.AnimationMode.EASE_OUT_QUAD,
@@ -1432,8 +1144,6 @@ class Workspace extends St.Widget {
         } else {
             // The window is hidden, make it shrink and fade it out
             clone.ease({
-                width: 0,
-                height: 0,
                 opacity: 0,
                 duration: Overview.ANIMATION_TIME,
                 mode: Clutter.AnimationMode.EASE_OUT_QUAD,
@@ -1447,6 +1157,11 @@ class Workspace extends St.Widget {
             this._overviewHiddenId = 0;
         }
 
+        if (this._overviewShownId) {
+            Main.overview.disconnect(this._overviewShownId);
+            this._overviewShownId = 0;
+        }
+
         if (this.metaWorkspace) {
             this.metaWorkspace.disconnect(this._windowAddedId);
             this.metaWorkspace.disconnect(this._windowRemovedId);
@@ -1454,32 +1169,20 @@ class Workspace extends St.Widget {
         global.display.disconnect(this._windowEnteredMonitorId);
         global.display.disconnect(this._windowLeftMonitorId);
 
-        if (this._repositionWindowsId > 0) {
-            GLib.source_remove(this._repositionWindowsId);
-            this._repositionWindowsId = 0;
-        }
-
-        if (this._positionWindowsId > 0) {
-            Meta.later_remove(this._positionWindowsId);
-            this._positionWindowsId = 0;
-        }
-
-        if (this._actualGeometryLater > 0) {
-            Meta.later_remove(this._actualGeometryLater);
-            this._actualGeometryLater = 0;
+        if (this._layoutFrozenId > 0) {
+            GLib.source_remove(this._layoutFrozenId);
+            this._layoutFrozenId = 0;
         }
 
         this._windows = [];
     }
 
-    // Sets this.leavingOverview flag to false.
     _doneLeavingOverview() {
-        this.leavingOverview = false;
+        this.layout_manager.layout_frozen = false;
     }
 
     _doneShowingOverview() {
-        this._animatingWindowsFade = false;
-        this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
+        this.layout_manager.layout_frozen = false;
     }
 
     _isMyWindow(window) {
@@ -1495,9 +1198,8 @@ class Workspace extends St.Widget {
     }
 
     // Create a clone of a (non-desktop) window and add it to the window list
-    _addWindowClone(metaWindow, positioned) {
+    _addWindowClone(metaWindow) {
         let clone = new WindowPreview(metaWindow, this);
-        clone.positioned = positioned;
 
         clone.connect('selected',
                       this._onCloneSelected.bind(this));
@@ -1510,9 +1212,6 @@ class Workspace extends St.Widget {
         clone.connect('drag-end', () => {
             Main.overview.endWindowDrag(metaWindow);
         });
-        clone.connect('size-changed', () => {
-            this._recalculateWindowPositions(WindowPositionFlags.NONE);
-        });
         clone.connect('show-chrome', () => {
             let focus = global.stage.key_focus;
             if (focus == null || this.contains(focus))
@@ -1524,10 +1223,10 @@ class Workspace extends St.Widget {
             });
         });
         clone.connect('destroy', () => {
-            this._removeWindowClone(metaWindow);
+            this._doRemoveWindow(metaWindow);
         });
 
-        this.add_child(clone);
+        this.layout_manager.addWindow(clone, metaWindow);
 
         if (this._windows.length == 0)
             clone.setStackAbove(null);
@@ -1546,94 +1245,14 @@ class Workspace extends St.Widget {
         if (index == -1)
             return null;
 
-        return this._windows.splice(index, 1).pop();
-    }
-
-    _isBetterLayout(oldLayout, newLayout) {
-        if (oldLayout.scale === undefined)
-            return true;
-
-        let spacePower = (newLayout.space - oldLayout.space) * LAYOUT_SPACE_WEIGHT;
-        let scalePower = (newLayout.scale - oldLayout.scale) * LAYOUT_SCALE_WEIGHT;
-
-        if (newLayout.scale > oldLayout.scale && newLayout.space > oldLayout.space) {
-            // Win win -- better scale and better space
-            return true;
-        } else if (newLayout.scale > oldLayout.scale && newLayout.space <= oldLayout.space) {
-            // Keep new layout only if scale gain outweighs aspect space loss
-            return scalePower > spacePower;
-        } else if (newLayout.scale <= oldLayout.scale && newLayout.space > oldLayout.space) {
-            // Keep new layout only if aspect space gain outweighs scale loss
-            return spacePower > scalePower;
-        } else {
-            // Lose -- worse scale and space
-            return false;
-        }
-    }
-
-    _getBestLayout(windows, area, rowSpacing, columnSpacing) {
-        // We look for the largest scale that allows us to fit the
-        // largest row/tallest column on the workspace.
-
-        let lastLayout = {};
-
-        let strategy = new UnalignedLayoutStrategy(this._monitor, rowSpacing, columnSpacing);
-
-        for (let numRows = 1; ; numRows++) {
-            let numColumns = Math.ceil(windows.length / numRows);
-
-            // If adding a new row does not change column count just stop
-            // (for instance: 9 windows, with 3 rows -> 3 columns, 4 rows ->
-            // 3 columns as well => just use 3 rows then)
-            if (numColumns == lastLayout.numColumns)
-                break;
-
-            let layout = { area, strategy, numRows, numColumns };
-            strategy.computeLayout(windows, layout);
-            strategy.computeScaleAndSpace(layout);
-
-            if (!this._isBetterLayout(lastLayout, layout))
-                break;
-
-            lastLayout = layout;
-        }
-
-        return lastLayout;
-    }
+        this.layout_manager.removeWindow(this._windows[index]);
 
-    _getSpacingAndPadding() {
-        let node = this.get_theme_node();
-
-        // Window grid spacing
-        let columnSpacing = node.get_length('-horizontal-spacing');
-        let rowSpacing = node.get_length('-vertical-spacing');
-        let padding = {
-            left: node.get_padding(St.Side.LEFT),
-            top: node.get_padding(St.Side.TOP),
-            bottom: node.get_padding(St.Side.BOTTOM),
-            right: node.get_padding(St.Side.RIGHT),
-        };
-
-        // All of the overlays have the same chrome sizes,
-        // so just pick the first one.
-        let clone = this._windows[0];
-        let [topBorder, bottomBorder] = clone.chromeHeights();
-        let [leftBorder, rightBorder] = clone.chromeWidths();
-
-        rowSpacing += (topBorder + bottomBorder) / 2;
-        columnSpacing += (rightBorder + leftBorder) / 2;
-        padding.top += topBorder;
-        padding.bottom += bottomBorder;
-        padding.left += leftBorder;
-        padding.right += rightBorder;
-
-        return [rowSpacing, columnSpacing, padding];
+        return this._windows.splice(index, 1).pop();
     }
 
-    _computeLayout(windows) {
-        let [rowSpacing, columnSpacing, padding] = this._getSpacingAndPadding();
-        let area = padArea(this._fullGeometry, padding);
-        return this._getBestLayout(windows, area, rowSpacing, columnSpacing);
+    _onStyleChanged() {
+        const themeNode = this.get_theme_node();
+        this.layout_manager.spacing = themeNode.get_length('spacing');
     }
 
     _onCloneSelected(clone, time) {
@@ -1666,15 +1285,6 @@ class Workspace extends St.Widget {
             if (this._isMyWindow(window))
                 return false;
 
-            // Set a hint on the Mutter.Window so its initial position
-            // in the new workspace will be correct
-            window._overviewHint = {
-                x: actor.x,
-                y: actor.y,
-                width: actor.width,
-                heigth: actor.height,
-            };
-
             // We need to move the window before changing the workspace, because
             // the move itself could cause a workspace change if the window enters
             // the primary monitor
index 591c2b46f0f76bcfcad80e1a4971847a15826ad5..9335da625f66ce609d113ae777fa2d2f4d4cc65a 100644 (file)
@@ -25,13 +25,9 @@ var WorkspacesViewBase = GObject.registerClass({
         this.connect('destroy', this._onDestroy.bind(this));
         global.focus_manager.add_group(this);
 
-        // The actor itself isn't a drop target, so we don't want to pick on its area
-        this.set_size(0, 0);
-
         this._monitorIndex = monitorIndex;
 
         this._fullGeometry = null;
-        this._actualGeometry = null;
 
         this._inDrag = false;
         this._windowDragBeginId = Main.overview.connect('window-drag-begin', this._dragBegin.bind(this));
@@ -63,12 +59,13 @@ var WorkspacesViewBase = GObject.registerClass({
 
     setFullGeometry(geom) {
         this._fullGeometry = geom;
-        this._syncFullGeometry();
     }
 
-    setActualGeometry(geom) {
-        this._actualGeometry = geom;
-        this._syncActualGeometry();
+    vfunc_allocate(box) {
+        this.set_allocation(box);
+
+        for (const child of this)
+            child.allocate_available_size(0, 0, box.get_width(), box.get_height());
     }
 });
 
@@ -100,12 +97,9 @@ class WorkspacesView extends WorkspacesViewBase {
                 this._updateWorkspaceActors(false);
             });
 
-
-        this._overviewShownId =
-            Main.overview.connect('shown', () => {
-                this.set_clip(this._fullGeometry.x, this._fullGeometry.y,
-                              this._fullGeometry.width, this._fullGeometry.height);
-            });
+        this._overviewShownId = Main.overview.connect('shown', () => {
+            this.clip_to_allocation = true;
+        });
 
         this._switchWorkspaceNotifyId =
             global.window_manager.connect('switch-workspace',
@@ -117,16 +111,6 @@ class WorkspacesView extends WorkspacesViewBase {
             this._workspaces[i].setReservedSlot(window);
     }
 
-    _syncFullGeometry() {
-        for (let i = 0; i < this._workspaces.length; i++)
-            this._workspaces[i].setFullGeometry(this._fullGeometry);
-    }
-
-    _syncActualGeometry() {
-        for (let i = 0; i < this._workspaces.length; i++)
-            this._workspaces[i].setActualGeometry(this._actualGeometry);
-    }
-
     getActiveWorkspace() {
         let workspaceManager = global.workspace_manager;
         let active = workspaceManager.get_active_workspace_index();
@@ -144,7 +128,7 @@ class WorkspacesView extends WorkspacesViewBase {
     }
 
     animateFromOverview(animationType) {
-        this.remove_clip();
+        this.clip_to_allocation = false;
 
         for (let w = 0; w < this._workspaces.length; w++) {
             if (animationType == AnimationType.ZOOM)
@@ -242,12 +226,8 @@ class WorkspacesView extends WorkspacesViewBase {
             }
         }
 
-        if (this._fullGeometry) {
+        if (this._fullGeometry)
             this._updateWorkspaceActors(false);
-            this._syncFullGeometry();
-        }
-        if (this._actualGeometry)
-            this._syncActualGeometry();
     }
 
     _activeWorkspaceChanged(_wm, _from, _to, _direction) {
@@ -353,14 +333,6 @@ class ExtraWorkspaceView extends WorkspacesViewBase {
         this._workspace.setReservedSlot(window);
     }
 
-    _syncFullGeometry() {
-        this._workspace.setFullGeometry(this._fullGeometry);
-    }
-
-    _syncActualGeometry() {
-        this._workspace.setActualGeometry(this._actualGeometry);
-    }
-
     getActiveWorkspace() {
         return this._workspace;
     }
@@ -452,6 +424,7 @@ class WorkspacesDisplay extends St.Widget {
         this._scrollEventId = 0;
         this._keyPressEventId = 0;
         this._scrollTimeoutId = 0;
+        this._syncActualGeometryLater = 0;
 
         this._actualGeometry = null;
         this._fullGeometry = null;
@@ -476,6 +449,11 @@ class WorkspacesDisplay extends St.Widget {
             this._parentSetLater = 0;
         }
 
+        if (this._syncActualGeometryLater) {
+            Meta.later_remove(this._syncActualGeometryLater);
+            this._syncActualGeometryLater = 0;
+        }
+
         if (this._scrollTimeoutId !== 0) {
             GLib.source_remove(this._scrollTimeoutId);
             this._scrollTimeoutId = 0;
@@ -755,7 +733,17 @@ class WorkspacesDisplay extends St.Widget {
         const height = this.allocation.get_height();
 
         this._actualGeometry = { x, y, width, height };
-        this._syncWorkspacesActualGeometry();
+
+        if (this._syncActualGeometryLater > 0)
+            return;
+
+        this._syncActualGeometryLater =
+            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
+                this._syncWorkspacesActualGeometry();
+
+                this._syncActualGeometryLater = 0;
+                return GLib.SOURCE_REMOVE;
+            });
     }
 
     _syncWorkspacesActualGeometry() {
@@ -765,7 +753,9 @@ class WorkspacesDisplay extends St.Widget {
         let monitors = Main.layoutManager.monitors;
         for (let i = 0; i < monitors.length; i++) {
             let geometry = i === this._primaryIndex ? this._actualGeometry : monitors[i];
-            this._workspacesViews[i].setActualGeometry(geometry);
+            const { x, y, width, height } = geometry;
+
+            this._workspacesViews[i].set({ x, y, width, height });
         }
     }